package com.example.rxtxdemo.rxtx.demo;

import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson2.JSONObject;
import com.example.rxtxdemo.rxtx.DataAvailableListener;
import com.example.rxtxdemo.rxtx.SerialPortListener;
import com.fazecast.jSerialComm.SerialPort;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
public class SerialPortManager {


    public static Map<String, SerialPort> COM_MAPS = Maps.newHashMap();

    /**
     * 查找所有可用端口
     *
     * @return {@link List}<{@link String}>
     */
    public static List<String> findPorts() {
        // 获得当前所有可用串口
        SerialPort[] serialPorts = SerialPort.getCommPorts();
        List<String> portNameList = Lists.newLinkedList();
        // 将可用串口名添加到List并返回该List
        for (SerialPort serialPort : serialPorts) {
            portNameList.add(serialPort.getSystemPortName());
        }
        //去重
        portNameList = portNameList.stream().distinct().collect(Collectors.toList());
        return portNameList;
    }

    /**
     * 打开串口
     *
     * @param portName 端口名称
     * @param baudRate 波特率
     * @return 串口对象
     */
    public static SerialPort openPort(String portName, Integer baudRate) {
        SerialPort serialPort = SerialPort.getCommPort(portName);
        if (baudRate != null) {
            serialPort.setBaudRate(baudRate);
        }
        //开启串口
        if (!serialPort.isOpen()) {
            serialPort.openPort(1000);
            COM_MAPS.put(serialPort.getSystemPortName(), serialPort);
        } else {
            return serialPort;
        }
        // 设置一下串口的波特率等参数
        // 数据位：8
        // 停止位：1
        // 校验位：None
        serialPort.setFlowControl(SerialPort.FLOW_CONTROL_DISABLED);
        if (null != baudRate) {
            serialPort.setComPortParameters(baudRate, 8, SerialPort.ONE_STOP_BIT, SerialPort.NO_PARITY);
        }
        serialPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING | SerialPort.TIMEOUT_WRITE_BLOCKING, 1000, 1000);
        return serialPort;
    }


    /**
     * 关闭串口
     *
     * @param serialPort 待关闭的串口对象
     */
    public static void closePort(SerialPort serialPort) {
        if (serialPort != null && serialPort.isOpen()) {
            serialPort.closePort();
            COM_MAPS.remove(serialPort.getSystemPortName());
        }
    }


    /**
     * 往串口发送数据
     *
     * @param serialPort 串口对象
     * @param content    待发送数据
     */
    public static void sendToPort(SerialPort serialPort, byte[] content) {
        if (!serialPort.isOpen()) {
            return;
        }
        serialPort.writeBytes(content, content.length);
    }

    /**
     * 从串口读取数据
     *
     * @param serialPort 当前已建立连接的SerialPort对象
     * @return 读取到的数据
     */
    public static byte[] readFromPort(SerialPort serialPort) {
        log.info("开始发送消息====》 {}", serialPort.bytesAvailable());
        byte[] reslutData = null;
        try {
            if (!serialPort.isOpen()) {
                return null;
            }
            int i = 0;
            while (serialPort.bytesAvailable() > 0 && i++ < 5) Thread.sleep(20);
            byte[] readBuffer = new byte[serialPort.bytesAvailable()];
            int numRead = serialPort.readBytes(readBuffer, readBuffer.length);
            if (numRead > 0) {
                reslutData = readBuffer;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return reslutData;
    }

    public static byte[] sendAndRead(SerialPort serialPort, byte[] content, long wait) {
        sendToPort(serialPort, content);
        ThreadUtil.sleep(wait);
        byte[] bytes = readFromPort(serialPort);
        closePort(serialPort);
        return bytes;
    }

    public static byte[] sendAndRead(String portName, Integer baudRate, byte[] content, long wait) {
        SerialPort serialPort = COM_MAPS.get(portName);
        log.info("已打开的串口信息 {}", JSONObject.toJSONString(COM_MAPS));
        if (null == serialPort) {
            serialPort = openPort(portName, baudRate);
            log.info("打开串口 {}", serialPort.isOpen());
        }
        sendToPort(serialPort, content);
        ThreadUtil.sleep(wait);
        return readFromPort(serialPort);
    }

    /**
     * 添加监听器
     * @param serialPort    串口对象
     * @param listener  串口存在有效数据监听
     */
    public static void addListener(SerialPort serialPort, DataAvailableListener listener) {
        try {
            // 给串口添加监听器
            serialPort.addDataListener(new SerialPortListener(listener));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}